package com.moorror.codegenvel.view.window.codegen.tree;

import com.google.common.collect.Lists;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.project.Project;
import com.moorror.codegenvel.common.dialog.DialogFormTreeHistory;
import com.moorror.codegenvel.common.dialog.MRDialog;
import com.moorror.codegenvel.common.dialog.MRDialogInputName;
import com.moorror.codegenvel.common.tree.MTTreeCell;
import com.moorror.codegenvel.common.tree.TreePanelMark;
import com.moorror.codegenvel.common.tree.TreeRightPanelJson;
import com.moorror.codegenvel.common.tree.actions.CopyGenNewTreeAction;
import com.moorror.codegenvel.common.tree.actions.DeleteRightContentSqliteAction;
import com.moorror.codegenvel.common.tree.actions.SaveRightContentSqliteAllAction;
import com.moorror.codegenvel.common.tree.actions.TransferCallbackTreeSelectAction;
import com.moorror.codegenvel.common.tree.actions.gencode.GenCodeExtractVelocityTemplateAction;
import com.moorror.codegenvel.common.tree.actions.gencode.GenCodeExtractVelocityTemplateCopyPathAction;
import com.moorror.codegenvel.common.tree.actions.gencode.GenCodeVelocityAction;
import com.moorror.codegenvel.common.tree.enums.AddSubTreeNodeType;
import com.moorror.codegenvel.db.sqlite.dao.BaseDAO;
import com.moorror.codegenvel.db.sqlite.dao.impl.CodeGenSceneDaoImpl;
import com.moorror.codegenvel.db.sqlite.dao.impl.CodeGenSceneTemplateDaoImpl;
import com.moorror.codegenvel.db.sqlite.dao.impl.CodeGenTemplateDaoImpl;
import com.moorror.codegenvel.db.sqlite.entity.AbEntity;
import com.moorror.codegenvel.db.sqlite.entity.CodeGenScene;
import com.moorror.codegenvel.db.sqlite.entity.CodeGenSceneTemplate;
import com.moorror.codegenvel.db.sqlite.entity.CodeGenTemplate;
import com.moorror.codegenvel.utils.GuiUtils;
import com.moorror.codegenvel.utils.HistoryTableUtils;
import com.moorror.codegenvel.utils.TreeCellEntityUtils;
import com.moorror.codegenvel.view.component.CodeGenByVelocityComponent;
import com.moorror.codegenvel.view.component.TabContentRightShow;
import com.moorror.codegenvel.view.window.codegen.CodeGenLeft;
import com.moorror.codegenvel.view.window.codegen.domain.ExtractFileDesc;
import com.moorror.codegenvel.view.window.codegen.view.CodeGenScenePanel;
import lombok.Getter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.Pair;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;

/**
 * @Author jiyanghuang
 * @Date 2024/4/11 23:14
 */
public class MTTreeCellCodeGenScene implements MTTreeCell {

    private Project project;

    private List<MTTreeCellCodeGenData> mockDatas = Lists.newArrayList();

    @Getter
    private TreeRightPanelJson treeRightPanelJson;

    @Getter
    private CodeGenScenePanel codeGenScenePanel;

    /**
     * 真实的数据对象
     */
    @Getter
    private CodeGenScene codeGenScene;

    public MTTreeCellCodeGenScene(Project project, CodeGenScene codeGenScene) {
        this.project = project;
        this.codeGenScene = codeGenScene;
    }


    @Override
    public String cellShow() {
        return codeGenScene.getName();
    }

    @Override
    public Icon iconSelected() {
        return GuiUtils.SCENE;
    }

    @Override
    public Icon iconUnselected() {
        return GuiUtils.SCENE;
    }

    @Override
    public AddSubTreeNodeType addSubTreeNodeType() {
        return AddSubTreeNodeType.DIALOG;
    }

    @Override
    public DefaultMutableTreeNode buildSubTreeNode(String jsonStr, TreePanelMark treePaneLMark) {
        CodeGenTemplate codeGenTemplate = CodeGenTemplate.of(jsonStr);
        codeGenScene.addChildren(codeGenTemplate);
        MTTreeCellCodeGenData mockScene = new MTTreeCellCodeGenData(project, codeGenTemplate);
        DefaultMutableTreeNode sequenceTreeNode = new DefaultMutableTreeNode(mockScene);
        return sequenceTreeNode;
    }

    @Override
    public void addSubTreeNodeDialog(JTree tree, DefaultMutableTreeNode mutabLeTreeNode, TreePanelMark treePaneLMark) {
        CodeGenLeft mockLeft = (CodeGenLeft) treePaneLMark;
        new MRDialogInputName("", "template name", mockLeft.fetchProject(), (form) -> {
            CodeGenTemplate codeGenTemplate = AbEntity.of(CodeGenTemplate.class);
            codeGenTemplate.setName(form.getInputName().getText());
            return BaseDAO.checkExistAdd(codeGenTemplate, CodeGenTemplateDaoImpl.getInstance(), CodeGenTemplate::getName, () -> {
                DefaultMutableTreeNode chiLdNode = buildSubTreeNode(form.getInputName().getText(), treePaneLMark);
                addSubTreeNode(tree, mutabLeTreeNode, treePaneLMark, chiLdNode);
                /**
                 * 添加关联关系
                 */
                CodeGenSceneTemplate codeGenSceneTemplate = AbEntity.of(CodeGenSceneTemplate.class);
                codeGenSceneTemplate.setScene(codeGenScene.getName());
                codeGenSceneTemplate.setTemplate(codeGenTemplate.getName());
                CodeGenSceneTemplate ua = BaseDAO.connWrap((conn) -> {
                    return CodeGenSceneTemplateDaoImpl.getInstance().insert(conn, codeGenSceneTemplate);
                });
                if(null == ua){
                    return Pair.of(false, " add sceneTemplate fail ");
                }
                return Pair.of(true, null);
            });
        }).ofDialogShow();
    }

    @Override
    public void treeSelectionListener(JTree tree, DefaultMutableTreeNode mutableTreeNode, TreePanelMark treePanelMark) {
        try {
            if (null == codeGenScenePanel) {
                codeGenScenePanel = new CodeGenScenePanel(project, codeGenScene);
            }
            TabContentRightShow tabContentRightShow = CodeGenByVelocityComponent.getInstance(project).findInstance(TabContentRightShow.class);
            tabContentRightShow.updatePanel(codeGenScenePanel);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public ActionGroup rightClickActionGroup(JTree tree, DefaultMutableTreeNode mutableTreeNode, DefaultActionGroup defaultActionGroup, TreePanelMark treePanelMark) {
        defaultActionGroup.add(new GenCodeVelocityAction(treePanelMark, "Gen code velocity", "Gen code velocity"));
        defaultActionGroup.add(new SaveRightContentSqliteAllAction(treePanelMark, "saveSceneToSqlite", "save mock scene to sqlite"));
        defaultActionGroup.add(new CopyGenNewTreeAction("Copy And Generate New Scene", "Copy And Generate New Scene", treePanelMark));
        defaultActionGroup.add(new DeleteRightContentSqliteAction(treePanelMark, "deleteSceneFromSqlite", "delete mock scene from sqlite"));
        defaultActionGroup.add(new GenCodeExtractVelocityTemplateAction(treePanelMark, "Extract Template", "Extract Template"));
        defaultActionGroup.add(new GenCodeExtractVelocityTemplateCopyPathAction(treePanelMark, "Extract Template Copy Path", "Extract Template Copy Path"));
        defaultActionGroup.add(new TransferCallbackTreeSelectAction(treePanelMark, "Save Params As History", "Save Params As History", AllIcons.Actions.SearchWithHistory, this::saveAsHistory));
        defaultActionGroup.add(new TransferCallbackTreeSelectAction(treePanelMark, "Select History", "Select History", AllIcons.Actions.SearchWithHistory, this::selectHistory));
        return defaultActionGroup;
    }

    @Override
    public void genCodeVelocity(TreePanelMark treePanelMark, DefaultMutableTreeNode mutableTreeNode) {
        if (mutableTreeNode.getChildCount() >= 0) {
            List<DefaultMutableTreeNode> genList = Lists.newArrayList();
            for (Enumeration<?> e = mutableTreeNode.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode) e.nextElement();
                if(n instanceof DefaultMutableTreeNode){
                    DefaultMutableTreeNode sub = (DefaultMutableTreeNode)n;
                    genList.add(sub);
                }
            }
            if(CollectionUtils.isNotEmpty(genList)){
                Collections.sort(genList, new Comparator<DefaultMutableTreeNode>() {
                    @Override
                    public int compare(DefaultMutableTreeNode o1, DefaultMutableTreeNode o2) {
                        String one = orderGen(o1);
                        String two = orderGen(o2);
                        return Integer.valueOf(one) - Integer.valueOf(two);
                    }
                });
                for(DefaultMutableTreeNode treeNode : genList){
                    MTTreeCellCodeGenData mtTreeCellCodeGenData = (MTTreeCellCodeGenData)treeNode.getUserObject();
                    mtTreeCellCodeGenData.genCodeVelocity(treePanelMark, treeNode);
                }
            }
        }
    }

    @Override
    public List<MTTreeCell> subTreeCell() {
        return (List) mockDatas;
    }

    public String velocityContext() {
        if (null == treeRightPanelJson) {
            return codeGenScene.getJsonContext();
        }
        return treeRightPanelJson.jsonValue();
    }

    @Override
    public void saveRightContentSqlite(TreePanelMark treePanelMark) {
        try {
            /**
             * 界面没有打开，没有填充数据
             */
            if(null == codeGenScenePanel){
                return;
            }
            /**
             * 右边得有统一的 fetchValue 然后保存
             */
            codeGenScenePanel.fetchValue();

            /**
             * 更新表
             */
            BaseDAO.update(CodeGenSceneDaoImpl.getInstance(), codeGenScene);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }


    @Override
    public void deleteRightContentFromSqlite(DefaultMutableTreeNode mutableTreeNode, TreePanelMark treePanelMark) {
        try {
            BaseDAO.manyToManyDelete(CodeGenSceneDaoImpl.getInstance(), CodeGenSceneTemplateDaoImpl.getInstance(), CodeGenTemplateDaoImpl.getInstance(), codeGenScene, (st, t) -> {
                CodeGenTemplate codeGenTemplate = (CodeGenTemplate) t;
                CodeGenSceneTemplate codeGenSceneTemplate = AbEntity.of(CodeGenSceneTemplate.class);
                codeGenSceneTemplate.setScene(st.getName());
                codeGenSceneTemplate.setTemplate(codeGenTemplate.getName());
                return codeGenSceneTemplate;
            });
            this.removeCurrent(treePanelMark.jTree(), mutableTreeNode);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void copyGenNewTree(TreePanelMark treePanelMark, DefaultMutableTreeNode mutableTreeNode) {
        CodeGenLeft mockLeft = (CodeGenLeft) treePanelMark;
        new MRDialogInputName("", "New Scene Name", treePanelMark.fetchProject(), (form) -> {
            CodeGenScene codeGenSceneNew = AbEntity.of(CodeGenScene.class);
            codeGenSceneNew.setName(form.getInputName().getText());
            return BaseDAO.checkExistAdd(codeGenSceneNew, CodeGenSceneDaoImpl.getInstance(), CodeGenScene::getName, () -> {
                if(CollectionUtils.isNotEmpty(codeGenScene.getChildren())){
                    BaseDAO.copyMMN(codeGenSceneNew.getName(),CodeGenSceneTemplateDaoImpl.getInstance(), codeGenScene.getChildren(), CodeGenSceneTemplate.class, null);
                }
                /**
                 * 更新树
                 */
                treePanelMark.treeReload(treePanelMark.rootTreeNode(), () -> {
                    List<CodeGenScene> codeGenScenes = CodeGenSceneDaoImpl.getInstance().searchLikeMTM(codeGenSceneNew.getName());
                    TreeCellEntityUtils.genTreeRootAppend(treePanelMark.rootTreeNode(), project, codeGenScenes);
                });
                return Pair.of(true, null);
            });
        }).ofDialogShow();
    }

    public Pair<Boolean, String> addTemplate(JTree tree, DefaultMutableTreeNode mutabLeTreeNode, TreePanelMark treePaneLMark, ExtractFileDesc extractFileDesc){
        CodeGenTemplate codeGenTemplate = AbEntity.of(CodeGenTemplate.class);
        codeGenTemplate.setName(extractFileDesc.getFileName());
        codeGenTemplate.setContent(extractFileDesc.getFileContent());
        return BaseDAO.checkExistAdd(codeGenTemplate, CodeGenTemplateDaoImpl.getInstance(), CodeGenTemplate::getName, () -> {
            DefaultMutableTreeNode chiLdNode = buildSubTreeNode(extractFileDesc.getFileName(), treePaneLMark);
            MTTreeCellCodeGenData cellCodeGenData = (MTTreeCellCodeGenData)chiLdNode.getUserObject();
            CodeGenTemplate codeGenTemplateR = cellCodeGenData.getCodeGenTemplate();
            codeGenTemplateR.setContent(extractFileDesc.getFileContent());
            addSubTreeNode(tree, mutabLeTreeNode, treePaneLMark, chiLdNode);
            /**
             * 添加关联关系
             */
            CodeGenSceneTemplate codeGenSceneTemplate = AbEntity.of(CodeGenSceneTemplate.class);
            codeGenSceneTemplate.setScene(codeGenScene.getName());
            codeGenSceneTemplate.setTemplate(codeGenTemplate.getName());
            CodeGenSceneTemplate ua = BaseDAO.connWrap((conn) -> {
                return CodeGenSceneTemplateDaoImpl.getInstance().insert(conn, codeGenSceneTemplate);
            });
            /**
             * 更新新添加的变量
             * 更新界面的展示
             */
            codeGenScene.contextKeyAppend(extractFileDesc.getContextKvMap());
            codeGenScenePanel.fillVelocityContext();
            /**
             * 更新表
             */
            codeGenScene.updateFillBlank();
            BaseDAO.update(CodeGenSceneDaoImpl.getInstance(), codeGenScene);
            if(null == ua){
                return Pair.of(false, " add sceneTemplate fail ");
            }
            return Pair.of(true, null);
        });
    }


    private String orderGen(DefaultMutableTreeNode sub) {
        String order = "100";
        if (sub.getUserObject() instanceof MTTreeCellCodeGenData) {
            MTTreeCellCodeGenData mtTreeCellCodeGenData = (MTTreeCellCodeGenData) sub.getUserObject();
            if (null != mtTreeCellCodeGenData && null != mtTreeCellCodeGenData.getCodeGenTemplate() && null != mtTreeCellCodeGenData.getCodeGenTemplate().getOrderGen()) {
                order = mtTreeCellCodeGenData.getCodeGenTemplate().getOrderGen();
            }
        }
        return order;
    }

    public void saveAsHistory(DefaultMutableTreeNode treeNode, TreePanelMark treePanelMark) {
        /**
         * 右边得有统一的 fetchValue 然后保存
         */
        codeGenScenePanel.fetchValue();

        HistoryTableUtils.sceneAdd(treePanelMark.fetchProject(), CodeGenSceneDaoImpl.NAME_TABLE, codeGenScene.historySave());
    }

    public void selectHistory(DefaultMutableTreeNode treeNode, TreePanelMark treePanelMark) {
        DialogFormTreeHistory dialogFormTreeHistory = new DialogFormTreeHistory(project, "History", CodeGenSceneDaoImpl.NAME_TABLE, this::updateSelect);
        MRDialog.of(dialogFormTreeHistory).show();
    }

    public void updateSelect(String jsonValue){
        codeGenScene.historyUpdate(jsonValue);
        try {
            codeGenScenePanel = new CodeGenScenePanel(project, codeGenScene);
            TabContentRightShow tabContentRightShow = CodeGenByVelocityComponent.getInstance(project).findInstance(TabContentRightShow.class);
            tabContentRightShow.updatePanel(codeGenScenePanel);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}


